

=========================================
===         Lode Runner NES           ===
===           Level Format            ===
===              v1.1                 ===
===             by Disch              ===
=========================================



THE INTRODUCTION:
-----------------------------------

This was a fun one to figure out.  They must have been really tight on space -- considering
this is only a 16K ROM.  Anyway the compression is pretty intricate, and everything is
bitpacked so that minimal space is wasted!  Additionally, *THERE IS NO POINTER TABLE*.
To work around this madness, the game will actually load every level up to the one you're
on (this is probably why you have to wait so long while it's playing that jingle at the
start of each level).

Of course bitpacked and no pointers also means editing these levels will be totally
impractical without a level editor.  You would need to unpack all the bits, decompress your
level, edit it, recompress it, then bitpack all the levels again.  A lot of work.


Anyway without further stalling:


THE TILESET:
-----------------------------------

There are 8 tiles:
  0 = open space
  1 = brick wall (diggable)
  2 = solid wall (not diggable)
  3 = ladder
  4 = rope (that you hang on / shimmie across)
  5 = fake floor (drop through)
  6 = goal ladder (appears after you've collected enough gold)
  7 = pile of gold


THE DIMENSIONS / OFFSETS:
-----------------------------------

- Maps consist of 14 rows
- Each row consists of 28 tiles
- Rows are stored sequentially, top row being stored first, bottom row stored last
- tiles in each row are stored left to right (usually)


Maps start at offset 0x02A88 (CPU address $EA78).  The pointer to the start of map data is
hardcoded -- if you want to change it (like, say, if you expand the ROM to add more space
for levels), the high byte ($EA) is at offset 0x0072E and the low byte ($78) is at offset
0x0071A.



THE BITPACKING:
-----------------------------------

The game "pulls" 1, 2, 3, or 5 bit values from the level data at a time, starting with the
high bit.  It does not read full bytes of the level data.  For example, given the following
bytes:

  (hex):  A2 67 12

You would have the following bitstring:

  (bin):  10100010 01100111 00010010

If the game pulled, in order, a 3 bit value, then a 2 bit value, then a 5 bit value, it'd
get 5, 0, and 9 respectively:

  (bin):  [101] [00] [01001] 100111 00010010
            5     0     9

You *never* skip over the remaining bits and go to the next byte.  EVERYTHING is bitpacked.
There is no guarantee that any level (other than level 1) will start cleanly on a byte
boundary.



OVERALL MAP STORAGE:
-----------------------------------

Each map consists of the following (stored in order):
 - 14 compression blocks, each compressing a single row
 - enemy data/positions (at least 1 enemy must exist per level)
 - player starting position

Immediately following the player position is the start of the next level's map.



ROW COMPRESSION BLOCKS:
-----------------------------------

Each row is represented by a single compression block.  The block starts with a 2-bit
header that indicates which type of block it is.  There are 4 different kinds of blocks.


<< Block 0 >>

Block 0 is a basic form of RLE.  It can contain any number of runs.

   2-bit : header.     Must be %00 to identify this block as block 0
   1-bit : control.    Set if there is more than 1 run

      {{ skip this section if control bit is clear }}
      5-bit : length of run.  Must not be 0 -- must not reach end of row
      3-bit : tile to run
      1-bit : control.  Set if there is yet another run
      {{ repeat until control bit is clear }}

   3-bit : tile to run.  This tile makes up the rest of the row.


Example:
  (hex):  26 12 92

  (bin):  00100110 00010010 10010010

  (bin):  00 1 00110 000 1 00101 001 0 010

        00 = header (identifies this as block 0)
         1 = control bit is set, so there is more than 1 run remaining
     00110 = run length of 6
       000 = tile ID of 0 ---> output tile 0 6 times
         1 = control bit is set, so there is more than 1 run remaining
     00101 = run length of 5
       001 = tile ID of 1 ---> output tile 1 5 times
         0 = control bit is clear, so only 1 run remaining
       010 = tile ID of 2 ---> output tile 2 until end of row

Decompresses to:  0000001111122222222222222222



<< Block 1 >>

Block 1 is a 1-bit palettized row.

  2-bit : header.    Must be %01 to identify this block as block 1
  3-bit : palette ... tile 'A'
  3-bit : palette ... tile 'B'

     {{ repeat this section 28 times -- once for each tile }}
     1-bit : palette index of this tile
     {{ }}


Example:
  (hex):  47 64 67 76 70

  (bin):  01000111 01100100 01100111 01110110 0111xxxx

  (bin):  01 000 111 0110010001100111011101100111

        01 = header (identifies this as block 1)
       000 = tile A in palette
       111 = tile B in palette
  the rest = 1 bit-per-tile "bitmap" of the row

Decompresses to:  0770070007700777077707700777



<< Block 2 >>

Block 2 basically is like "this row is all tile 0, except for..." and then lists each tile
individually.

  2-bit : header.    %10 for block 2
  1-bit : control.   Set if there are tiles that are nonzero

     {{ skip this section if control bit is clear }}
     3-bit : tile ID
     5-bit : tile X position (must be < $1C)
     1-bit : control.  Set if there are more tiles that are nonzero
     {{ repeat this section until control bit is clear

Example:
  (hex):  BA 32 20
  
  (bin):  10111010 00110010 00100xxx

  (bin):  10 1 110 10001 1 001 00010 0

        10 = header (identifies as block 2)
         1 = control bit is set... there's at least 1 tile that's nonzero
       110 = the tile ID
     10001 = it's X position
         1 = control bit.  Set again, so there's another one
       001 = tile ID
     00010 = X position
         0 = control bit.  This time it's clear, so we're done

Decompresses to:  0010000000000000060000000000



<< Block 3 >>

This is two blocks in one.  One is an uncompressed block (but still bitpacked), and the
other is a 2-bits per tile "bitmap" similar to Block 1.

To switch between the two there's an additional (or secondary) header bit that comes
after the normal 2-byte header:

I won't give examples for either type, because Block 3B is totally straightforward
and Block 3A is similar to Block 1 in concept.


<< Block 3A >>

  2-bit : header.            Must be %11
  1-bit : secondary header.  Must be 0  (if 1, use Block 3B instead)
  3-bit : palette ... tile 'A'
  3-bit : palette ... tile 'B'
  3-bit : palette ... tile 'C'
  3-bit : palette ... tile 'D'

     {{ repeat this section 28 times -- once for each tile }}
     2-bit : palette index of this tile
     {{ }}



<< Block 3B >>

This is the uncompressed version of block 3:

  2-bit : header.            Must be %11
  1-bit : secondary header.  Must be 1  (if 0, use Block 3A instead)

     {{ repeat this section 28 times -- once for each tile }}
     3-bit : tile to output
     {{ }}



ENEMY/PLAYER POSITIONS:
-----------------------------------

Immediately following the row blocks is the enemy info:

   3-bit : number of enemies (must not be zero)

      {{ for each enemy }}
      5-bit : X position (must be < $1C)
      5-bit : Y position (must be < $0E)
      {{ repeat for each enemy }}

Note that even though Y position could be a 4-bit value because it can't be above $0D...
the game actually reads a full 5-bit value... probably only because the game has no 4-bit
reading routine.

Following that is another pair of 5-bit values that specify the player's starting position.

And of course, immediately following the player position is the start of the level data for
the next level!  Remember it's all bitpacked!


That's it!

